package com.atguigu.tingshu.order.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.IdUtil;
import com.atguigu.tingshu.account.AccountFeignClient;
import com.atguigu.tingshu.album.AlbumFeignClient;
import com.atguigu.tingshu.common.constant.RedisConstant;
import com.atguigu.tingshu.common.constant.SystemConstant;
import com.atguigu.tingshu.common.delay.DelayMsgService;
import com.atguigu.tingshu.common.execption.GuiguException;
import com.atguigu.tingshu.common.result.Result;
import com.atguigu.tingshu.common.result.ResultCodeEnum;
import com.atguigu.tingshu.common.util.AuthContextHolder;
import com.atguigu.tingshu.model.album.AlbumInfo;
import com.atguigu.tingshu.model.album.TrackInfo;
import com.atguigu.tingshu.model.order.OrderDerate;
import com.atguigu.tingshu.model.order.OrderDetail;
import com.atguigu.tingshu.model.order.OrderInfo;
import com.atguigu.tingshu.model.user.UserInfo;
import com.atguigu.tingshu.model.user.VipServiceConfig;
import com.atguigu.tingshu.order.helper.SignHelper;
import com.atguigu.tingshu.order.mapper.OrderDerateMapper;
import com.atguigu.tingshu.order.mapper.OrderDetailMapper;
import com.atguigu.tingshu.order.mapper.OrderInfoMapper;
import com.atguigu.tingshu.order.service.OrderInfoService;
import com.atguigu.tingshu.user.client.UserFeignClient;
import com.atguigu.tingshu.vo.account.AccountLockVo;
import com.atguigu.tingshu.vo.order.OrderDerateVo;
import com.atguigu.tingshu.vo.order.OrderDetailVo;
import com.atguigu.tingshu.vo.order.OrderInfoVo;
import com.atguigu.tingshu.vo.order.TradeVo;
import com.atguigu.tingshu.vo.user.UserInfoVo;
import com.atguigu.tingshu.vo.user.UserPaidRecordVo;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import io.seata.spring.annotation.GlobalTransactional;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Slf4j
@Service
@SuppressWarnings({"all"})
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {

    @Autowired
    private OrderInfoMapper orderInfoMapper;

    @Autowired
    private UserFeignClient userFeignClient;

    @Autowired
    private AlbumFeignClient albumFeignClient;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private AccountFeignClient accountFeignClient;

    @Autowired
    private OrderDetailMapper orderDetailMapper;

    @Autowired
    private OrderDerateMapper orderDerateMapper;

    @Autowired
    private DelayMsgService delayMsgService;


    /**
     * 订单确认
     * @param tradeVo
     * @return
     */
    @Override
    public OrderInfoVo getTradeOrderData(TradeVo tradeVo) {
        OrderInfoVo orderInfoVo = new OrderInfoVo();
        Long userId = AuthContextHolder.getUserId();
        // 本次结算流水号-防止重复提交
        // 构建当前用户本次订单流水号Key
        String tradeNoKey = RedisConstant.ORDER_TRADE_NO_PREFIX + userId;
        // 生成本次订单流水号
        String tradeNo = IdUtil.fastSimpleUUID();
        // 将流水号存入Redis
        redisTemplate.opsForValue().set(tradeNoKey, tradeNo, 5, TimeUnit.MINUTES);
        // 封装订单VO中流水号
        orderInfoVo.setTradeNo(tradeNo);
        //获取付款项目类型: 1001-专辑 1002-声音 1003-vip会员
        String itemType = tradeVo.getItemType();
        orderInfoVo.setItemType(itemType);
        //付款项目类型Id
        Long itemId = tradeVo.getItemId();
        //针对声音购买，购买当前集往后多少集
        Integer trackCount = tradeVo.getTrackCount();
        //初始化订单原始金额
        BigDecimal originalAmount = new BigDecimal(0.00);
        //初始化减免金额
        BigDecimal derateAmount = new BigDecimal("0.00");
        //初始化订单总价
        BigDecimal orderAmount = new BigDecimal(0.00);
        //订单明细列表
        List<OrderDetailVo> orderDetailVoList = new ArrayList<>();
        //订单减免列表
        List<OrderDerateVo> orderDerateVoList = new ArrayList<>();

        if (SystemConstant.ORDER_ITEM_TYPE_ALBUM.equals(itemType)) {
            //如果是专辑购买
            //TODO 调用专辑微服务获取专辑信息
            Boolean ifbuy = userFeignClient.isPaidAlbum(itemId).getData();
            if (ifbuy){
                throw new GuiguException(400, "当前用户已购买该专辑！");
            }
            UserInfoVo userInfoVo = userFeignClient.getUserInfoVo(userId).getData();
            Assert.notNull(userInfoVo, "用户信息为空！");
            Integer isVip = userInfoVo.getIsVip();
            AlbumInfo albumInfo = albumFeignClient.getAlbumInfo(itemId).getData();
            Assert.notNull(albumInfo, "专辑信息为空");
            originalAmount = albumInfo.getPrice();
            orderAmount = originalAmount;
            //判断普通用户的价格
            BigDecimal discount = albumInfo.getDiscount();
            if (discount.intValue() != -1){
                if (isVip.intValue() == 0){
                    orderAmount = originalAmount.multiply(discount).divide(new BigDecimal(10), 2, RoundingMode.HALF_UP);
                }
                if (isVip.intValue() == 1 && new Date().after(userInfoVo.getVipExpireTime())){
                    orderAmount = originalAmount.multiply(discount).divide(new BigDecimal(10), 2, RoundingMode.HALF_UP);
                }
            }
            //判断是否有vip优惠
            BigDecimal vipDiscount = albumInfo.getVipDiscount();
            if (vipDiscount.intValue() != -1) {
                if (isVip.intValue() == 1 && new Date().before(userInfoVo.getVipExpireTime())){
                    orderAmount = originalAmount.multiply(vipDiscount).divide(new BigDecimal(10), 2, RoundingMode.HALF_UP);
                }
            }
            derateAmount = originalAmount.subtract(orderAmount);
            //封装订单中商品明细列表
            OrderDetailVo orderDetailVo = new OrderDetailVo();
            orderDetailVo.setItemId(tradeVo.getItemId());
            orderDetailVo.setItemName(albumInfo.getAlbumTitle());
            orderDetailVo.setItemUrl(albumInfo.getCoverUrl());
            orderDetailVo.setItemPrice(originalAmount);
            orderDetailVoList.add(orderDetailVo);

            //封装订单中优惠明细列表
            OrderDerateVo orderDerateVo = new OrderDerateVo();
            orderDerateVo.setDerateType(SystemConstant.ORDER_DERATE_VIP_SERVICE_DISCOUNT);
            orderDerateVo.setDerateAmount(derateAmount);
            orderDerateVo.setRemarks("专辑优惠：" + derateAmount);
            orderDerateVoList.add(orderDerateVo);

        } else if (SystemConstant.ORDER_ITEM_TYPE_TRACK.equals(itemType)) {
            //如果是声音购买
            //TODO 调用声音微服务获取声音信息
            List<TrackInfo> TrackInfoList = albumFeignClient.findPaidTrackInfoList(itemId, trackCount).getData();
            if(CollectionUtil.isEmpty(TrackInfoList)){
                throw new GuiguException(400, "无符合要求声音");
            }
            AlbumInfo albumInfo = albumFeignClient.getAlbumInfo(TrackInfoList.get(0).getAlbumId()).getData();
            if (albumInfo == null) {
                throw new GuiguException(400, "专辑不存在");
            }
            BigDecimal price = albumInfo.getPrice();
            originalAmount = price.multiply(new BigDecimal(TrackInfoList.size()));
            orderAmount = originalAmount;
            orderDetailVoList = TrackInfoList.stream().map(trackInfo -> {
                OrderDetailVo orderDetailVo = new OrderDetailVo();
                orderDetailVo.setItemId(trackInfo.getId());
                orderDetailVo.setItemName(trackInfo.getTrackTitle());
                orderDetailVo.setItemUrl(trackInfo.getCoverUrl());
                orderDetailVo.setItemPrice(price);
                return orderDetailVo;
            }).collect(Collectors.toList());


        } else if (SystemConstant.ORDER_ITEM_TYPE_VIP.equals(itemType)) {
            //如果购买vip会员
            //根据id获取详情信息
            VipServiceConfig vipServiceConfig = userFeignClient.getVipServiceConfig(itemId).getData();
            Assert.notNull(vipServiceConfig, "VIP套餐：{}不存在", tradeVo.getItemId());
            originalAmount = vipServiceConfig.getPrice();
            orderAmount = vipServiceConfig.getDiscountPrice();
            derateAmount = originalAmount.subtract(orderAmount);


            //封装订单中商品明细列表
            OrderDetailVo orderDetailVo = new OrderDetailVo();
            orderDetailVo.setItemId(tradeVo.getItemId());
            orderDetailVo.setItemName(vipServiceConfig.getName());
            orderDetailVo.setItemUrl(vipServiceConfig.getImageUrl());
            orderDetailVo.setItemPrice(originalAmount);
            orderDetailVoList.add(orderDetailVo);

            //封装订单中优惠明细列表
            OrderDerateVo orderDerateVo = new OrderDerateVo();
            orderDerateVo.setDerateType(SystemConstant.ORDER_DERATE_VIP_SERVICE_DISCOUNT);
            orderDerateVo.setDerateAmount(derateAmount);
            orderDerateVo.setRemarks("VIP限时优惠：" + derateAmount);
            orderDerateVoList.add(orderDerateVo);
        }

        orderInfoVo.setOriginalAmount(originalAmount);
        orderInfoVo.setDerateAmount(derateAmount);
        orderInfoVo.setOrderAmount(orderAmount);
        orderInfoVo.setOrderDetailVoList(orderDetailVoList);
        orderInfoVo.setOrderDerateVoList(orderDerateVoList);

        //时间戳
        orderInfoVo.setTimestamp(DateUtil.current());
        // 本次结算签名--防止数据篡改
        // 将订单VO转为Map-将VO中支付方式null值去掉
        Map<String, Object> paramsMap = BeanUtil.beanToMap(orderInfoVo, false, true);
        // 调用签名API对现有订单所有数据进行签名
        String sign = SignHelper.getSign(paramsMap);
        orderInfoVo.setSign(sign);

        return orderInfoVo;
    }

    /**
     * 提交订单
     * @param orderInfoVo
     * @return
     */
    @Override
    @GlobalTransactional(rollbackFor = Exception.class)
    public Map<String,String> submitOrder(OrderInfoVo orderInfoVo) {
        Long userId = AuthContextHolder.getUserId();
        //校验tradeNo
        String tradeNoKey = RedisConstant.ORDER_TRADE_NO_PREFIX + userId;
        String scriptText = "if(redis.call('get', KEYS[1]) == ARGV[1]) then return redis.call('del', KEYS[1]) else return 0 end";
        DefaultRedisScript<Boolean> redisScript = new DefaultRedisScript<>(scriptText, Boolean.class);
        Boolean istradeNo = (Boolean)redisTemplate.execute(redisScript, Arrays.asList(tradeNoKey), orderInfoVo.getTradeNo());
        if (!istradeNo){
            throw new GuiguException(400, "请勿重复提交");
        }
        //校验签名
        // 将订单VO转为Map-将VO中支付方式null值去掉
        Map<String, Object> paramsMap = BeanUtil.beanToMap(orderInfoVo, false, true);
        paramsMap.remove("payWay");
        // 调用签名API对现有订单所有数据进行签名
        String sign = SignHelper.getSign(paramsMap);
        if (!sign.equals(orderInfoVo.getSign())){
            throw new GuiguException(400, "签名错误");
        }

        //保存订单信息
        OrderInfo orderInfo = this.saveOrder(orderInfoVo, userId);


        //判断支付方式
        //如果是余额支付
        if (SystemConstant.ORDER_PAY_ACCOUNT.equals(orderInfoVo.getPayWay())){
            //更新余额
            AccountLockVo accountLockVo = new AccountLockVo();
            accountLockVo.setOrderNo(orderInfo.getOrderNo());
            accountLockVo.setUserId(userId);
            accountLockVo.setAmount(orderInfo.getOrderAmount());
            accountLockVo.setContent(orderInfo.getOrderTitle());
            Result deductResult = accountFeignClient.checkAndLock(accountLockVo);
            if (200 != deductResult.getCode()) {
                //扣减余额失败：全局事务都需要回滚
                throw new GuiguException(ResultCodeEnum.ACCOUNT_LESS);
            }
            UserPaidRecordVo userPaidRecordVo = new UserPaidRecordVo();
            userPaidRecordVo.setUserId(userId);
            userPaidRecordVo.setItemType(orderInfoVo.getItemType());
            userPaidRecordVo.setItemIdList(orderInfoVo.getOrderDetailVoList().stream().map(OrderDetailVo::getItemId).collect(Collectors.toList()));
            userPaidRecordVo.setOrderNo(orderInfo.getOrderNo());
            //保存订单信息
            Result paidRecordResult = userFeignClient.savePaidRecord(userPaidRecordVo);
            if (200 != paidRecordResult.getCode()) {
                //新增购买记录失败：全局事务都需要回滚
                throw new GuiguException(211, "新增购买记录异常");
            }
            //修改订单状态
            orderInfoMapper.update(null, new UpdateWrapper<OrderInfo>().set("order_status", SystemConstant.ORDER_STATUS_PAID).eq("id", orderInfo.getId()));
        }

        delayMsgService.sendDelayMessage("order:status:queue", orderInfo.getOrderNo(), 60);

        Map<String, String> mapResult = new HashMap<>();
        mapResult.put("orderNo", orderInfo.getOrderNo());

        return mapResult;
    }

    /**
     * 根据订单号获取订单信息
     * @param orderNo
     * @return
     */
    @Override
    public OrderInfo getOrderInfo(String orderNo) {
        OrderInfo orderInfo = orderInfoMapper.selectOne(new QueryWrapper<OrderInfo>().eq("order_no", orderNo));
        orderInfo.setOrderStatusName(this.parseOrderStatus(orderInfo.getOrderStatus()));
        orderInfo.setPayWayName(this.parsePayWay(orderInfo.getPayWay()));
        orderInfo.setOrderDetailList(orderDetailMapper.selectList(new QueryWrapper<OrderDetail>().eq("order_id", orderInfo.getId())));
        return orderInfo;
    }

    /**
     * 解析支付方式
     * @param payWay
     * @return
     */
    @Override
    public String parsePayWay(String payWay) {
        switch (payWay) {
            case SystemConstant.ORDER_PAY_WAY_WEIXIN:
                return "微信支付";
            case SystemConstant.ORDER_PAY_WAY_ALIPAY:
                return "支付宝支付";
            case SystemConstant.ORDER_PAY_ACCOUNT:
                return "账户余额支付";
        }
        return "";
    }

    /**
     * 解析订单状态
     * @param orderStatus
     * @return
     */
    @Override
    public String parseOrderStatus(String orderStatus) {
        switch (orderStatus) {
            case SystemConstant.ORDER_STATUS_UNPAID:
                return "未支付";
            case SystemConstant.ORDER_STATUS_PAID:
                return "已支付";
            case SystemConstant.ORDER_STATUS_CANCEL:
                return "已取消";
        }
        return "";
    }

    /**
     * 保存订单相关信息
     * @param orderInfoVo
     */
    @Override
    public OrderInfo saveOrder(OrderInfoVo orderInfoVo, Long userId) {
        OrderInfo orderInfo = BeanUtil.copyProperties(orderInfoVo, OrderInfo.class);
        orderInfo.setUserId(userId);
        orderInfo.setOrderTitle(orderInfoVo.getOrderDetailVoList().get(0).getItemName());
        orderInfo.setOrderNo(DateUtil.today().replace("-", "") + IdUtil.getSnowflakeNextIdStr());
        orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_UNPAID);
        orderInfoMapper.insert(orderInfo);
        Long orderId = orderInfo.getId();
        //保存订单明细信息
        List<OrderDetail> orderDetailList = orderInfoVo.getOrderDetailVoList().stream().map(orderDetailVo -> {
            OrderDetail orderDetail = BeanUtil.copyProperties(orderDetailVo, OrderDetail.class);
            orderDetail.setOrderId(orderId);
            orderDetailMapper.insert(orderDetail);
            return orderDetail;
        }).collect(Collectors.toList());

        //保存订单折扣明细信息
        List<OrderDerate> orderDerateList = orderInfoVo.getOrderDerateVoList().stream().map(orderDerateVo -> {
            OrderDerate orderDerate = BeanUtil.copyProperties(orderDerateVo, OrderDerate.class);
            orderDerate.setOrderId(orderId);
            orderDerateMapper.insert(orderDerate);
            return orderDerate;
        }).collect(Collectors.toList());
        return orderInfo;
    }

    /**
     * 查询用户订单分页列表
     * @param orderInfoPage
     * @param userId
     * @return
     */
    @Override
    public Page<OrderInfo> findUserPage(Page<OrderInfo> orderInfoPage, Long userId) {
        Page<OrderInfo> orderInfoPageResult = orderInfoMapper.selectUserPage(orderInfoPage, userId);
        orderInfoPageResult.getRecords().forEach(item -> {
            item.setOrderStatus(this.parseOrderStatus(item.getOrderStatus()));
            item.setPayWay(this.parsePayWay(item.getPayWay()));
        });
        return orderInfoPageResult;
    }

    /**
     * 延迟关单
     * @param string
     */
    @Override
    public void updateOrderStatus(String orderNo) {
        //todo 查询微信支付的返回结果
        OrderInfo orderInfo = orderInfoMapper.selectOne(new QueryWrapper<OrderInfo>().eq("order_no", orderNo));
        if (orderInfo != null && SystemConstant.ORDER_STATUS_PAID.equals(orderInfo.getOrderStatus())){
            return;
        }
        //修改订单信息
        orderInfoMapper.update(null, new UpdateWrapper<OrderInfo>().set("order_status", SystemConstant.ORDER_STATUS_CANCEL).eq("order_no", orderNo));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void paySuccess(String orderNo) {
        //修改订单信息
        OrderInfo orderInfo = this.getOrderInfo(orderNo);
        if (orderInfo != null && SystemConstant.ORDER_STATUS_PAID.equals(orderInfo.getOrderStatus())){
            return;
        }
        orderInfo.setOrderStatus(SystemConstant.ORDER_STATUS_PAID);
        orderInfo.setUpdateTime(new Date());
        orderInfoMapper.updateById(orderInfo);

        //新增用户支付信息
        UserPaidRecordVo userPaidRecordVo = new UserPaidRecordVo();
        userPaidRecordVo.setOrderNo(orderNo);
        userPaidRecordVo.setUserId(orderInfo.getUserId());
        userPaidRecordVo.setItemType(orderInfo.getItemType());
        List<Long> itemIdList = orderInfo.getOrderDetailList().stream().map(OrderDetail::getItemId).collect(Collectors.toList());
        userPaidRecordVo.setItemIdList(itemIdList);
        Result result = userFeignClient.savePaidRecord(userPaidRecordVo);
        if (200 != result.getCode()) {
            throw new GuiguException(500, "新增购买记录异常！");
        }
    }

}
